#
# This is Garth A. Dickie's "magic" Java makefile.  It doesn't solve all
# of your problems, but it does help a little bit.  Drop this makefile
# into the top level of a package heierarchy (make sure to call it `makefile'),
# and type `make' to update all `.class' files.  Type `make makefiles' to
# link the makefile into all subdirectories, so that you can type `make'
# in any subdirectory to update the `.class' files in that directory.
#
# If you use a Java compiler other than javac, or want to use this
# makefile to copy `.class' files to your web server, edit the
# variable definitions below (just past the list of targets).
#

#
# Targets:
#     all (this is the default target)
#         Update all `.class' files, in this directory and any subdirectories.
#
#     run
#         Update all `.class' files, then use appletviewer to start any applets
#         referenced by the file `index.html' in the current directory.
#
#     debug
#         Update all `.class' files, then use appletviewer with the -debug
#         option to start the java debugger on any applets referenced by the
#         file `index.html' in the current directory.
#
#     clean
#         Delete all `.class' files in this directory and any subdirectories.
#
#     public
#         Update all `.class' files, then copy all `.class' files to the directory
#         PUBLICDIR, creating subdirectories as neccessary.  Then intent is
#         that PUBLICDIR is the directory you use as your CODEBASE when you
#         include applets in your web pages.
#
#     release
#         *Don't* update any `.class' files.  Copy all files referenced in the
#         file `releasefiles' into the directory RELEASEDIR.  Repeat for each
#         subdirectory, creating subdirectories of RELEASEDIR as neccessary.
#         The intent is that you only wish to make certain files available
#         through a public release; you `make release' and then construct
#         `.tar.gz' files for release (by hand, or with another makefile).
#         Also, touch the file RELEASEDIR/../.release
#
#     sourcerelease
#         Copy all `.java' files into the directory SOURCERELEASEDIR.
#
#     changepackage OLD=... NEW=...
#         Change all lines in `.java' files which begin with `package OLD' or
#         `import OLD' to `package NEW' and `import NEW' respectively.  Note
#         that to change ibook.idvi.v10 to ibook.idvi.v11, you have to give the 
#         entire package name; OLD=v10 NEW=v11 won't work.
#
#     makefiles
#         Create a makefile with the same functionality in each subdirectory.
#         (Really just create a link to this makefile).  This is useful for
#         doing development work in subdirectories, but is not neccessary if
#         you are just going to `make all' or `make public'.
#
#     nomakefiles
#         Delete the makefiles in any subdirectories (if they are identical
#         to this makefile).
#

#
# Variables:
#     PUBLICDIR
#         Target directory for `make public'.  This should be the directory
#         (accessible from your web server) which you use as your CODEBASE
#         when including applets in your pages.
#

PUBLICDIR = /u/www/root/java/idvi/wwwlib/classes/

#
#     RELEASEDIR
#         Target directory for `make release'.  This can be any directory.
#         This is used for building a subset of your classes for release.
#

RELEASEDIR = ${HOME}/idvi/release/v10/classes/

#
#     SOURCERELEASEDIR
#         Target directory for `make sourcerelease'.
#

SOURCERELEASEDIR = ${HOME}/idvi/release/v10/idvisource_1.0/

#
#     JAVAC
#         The name of your Java compiler.
#

JAVAC = javac

#
#     JFLAGS
#         Options for the Java compiler.
#

JFLAGS = 

#
#     APPLETVIEWER
#         The name of the application you use for viewing applets.
#

APPLETVIEWER = appletviewer

MAKE = /usr/ccs/bin/make

########################################################################
#                                                                      #
# Don't change anything after this line.                               #
#                                                                      #
########################################################################

#
# About the scripts:
#
# Most targets in this makefile use shell scripts to do their work.  These
# scripts are recursive, doing some work in a directory and then recursing
# on the subdirectories.  This is achieved by defining a function which does
# the real work, and which can call itself in order to recurse.  This function
# is invoked once from the script, immediately after its definition.
#

#
# The target `all' uses `find' to create a list of all `.java' files in the
# current directory and subdirectories.  Then `sed' and `tr' are used to make
# this into a list of `.class' files which is passed to `make allclasses'.
# `make allclasses' just prints the names of the '.java' files which need
# to be compiled.  This list is then passed to JAVAC.
#
# This scheme is roughly 4 times faster than invoking JAVAC for each target
# (for the package that I am building), since the compiler only has to read
# the imported class definitions once.
#

all :
	@ \
	CLASSES=`find . -name '*.java' -print | sed 's/java$$/class/' | tr '\012' ' '`; \
	if [ "$$CLASSES" ]; then \
		COMPILE=`${MAKE} -n allclasses CLASSES="$$CLASSES"`; \
	fi; \
	if [ "$$COMPILE" ]; then \
		echo ${JAVAC} ${JFLAGS} $$COMPILE; \
		${JAVAC} ${JFLAGS} $$COMPILE; \
	fi

#
# `allclasses' is the only target which actually uses dependencies.
# This target is used by the script for the target `all', and will
# always be invoked with `make -n allclasses CLASSES=...'.  For each
# `.class' file which needs to be updated, we just echo the name of
# the corresponding `.java' file.
# 

.SUFFIXES :
.SUFFIXES : .java .class

.java.class :
	$<

allclasses : ${CLASSES}

#
# `run' uses `all' to build everything, and then invokes the APPLETVIEWER.
#

run : all
	@ \
	if [ -f index.html ]; then \
		echo ${APPLETVIEWER} index.html; \
		${APPLETVIEWER} index.html; \
	else \
		echo "make run: no file \"index.html\""; \
	fi

#
# `debug' uses `all' to build everything, and then invokes the APPLETVIEWER.
# with the option -debug, to start jdb.
#

debug : all
	@ \
	if [ -f index.html ]; then \
		echo ${APPLETVIEWER} -debug index.html; \
		${APPLETVIEWER} -debug index.html; \
	else \
		echo "make debug: no file \"index.html\""; \
	fi

#
# `clean' deletes all .class files in this directory and any subdirectories.
#
# The function `doclean' is recursive, deleting all `.class' files in
# the current directory, and then any found in subdirectories.  The
# parameter $1 is the current subdirectory.
#

clean :
	@ \
	doclean( ) { \
		echo "rm -f $$1*.class"; \
		rm -f *.class; \
		for PACKAGE in *; do \
			if [ -d $$PACKAGE -a ! -h $$PACKAGE ]; then \
				cd $$PACKAGE; \
				doclean $$1$$PACKAGE/; \
				cd ..; \
			fi; \
		done; \
	}; \
	doclean "";

#
# `public' uses `all' to build everything, and then copies all `.class'
# files into the PUBLICDIR heierarchy.
#
# The function `findpath' finds the position of the current directory in
# the class heierarchy.
#
# The function `makepath' creates a target directory if neccessary,
# creating any missing parent directories as well.  The parameter $1
# is the root of the path, and $2 is the subpath to be created.
# Since this is to be public, the directories are all made world
# readable and executable.
#
# The function `dopublic' is recursive, copying all `.class' files
# in the current directory and any subdirectories into the PUBLICDIR
# heierarchy.  The parameter $1 is the name of the subdirectory from
# which `make' was invoked, and $2 is the current subdirectory.
#

public : all
	@ \
	findpath( ) { \
		THISDIR=`pwd`; \
		while cmp -s makefile ../makefile; do \
			cd ..; \
		done; \
		ROOTDIR=`pwd`; \
		if [ $$THISDIR != $$ROOTDIR ]; then \
			expr $$THISDIR/ : $$ROOTDIR/"\(.*\)"; \
		fi; \
	}; \
	makepath( ) { \
		if [ ! -d $$1$$2 ]; then \
			if [ $$2 ]; then \
				makepath $$1 `echo $$2 | sed 's/[^/]*\/$$//'`; \
			fi; \
			echo mkdir $$1$$2; \
			mkdir $$1$$2; \
			echo chmod go+rx $$1$$2; \
			chmod go+rx $$1$$2; \
		fi; \
	}; \
	dopublic( ) { \
		for PACKAGE in *; do \
			if [ -d $$PACKAGE -a ! -h $$PACKAGE ]; then \
				cd $$PACKAGE; \
				dopublic $$1 $$2$$PACKAGE/; \
				cd ..; \
			fi; \
		done; \
		if [ -f *.class ]; then \
			makepath ${PUBLICDIR}/ $$1$$2; \
			echo cp "$$2*.class" ${PUBLICDIR}/$$1$$2; \
			cp *.class ${PUBLICDIR}/$$1$$2; \
			echo chmod go+r ${PUBLICDIR}/$$1$$2"*.class"; \
			chmod go+r ${PUBLICDIR}/$$1$$2*.class; \
		fi; \
	}; \
	dopublic `findpath` ""

#
# `release'
#
# The function `findpath' finds the position of the current directory in
# the class heierarchy.
#
# The function `makepath' creates a target directory if neccessary,
# creating any missing parent directories as well.  The parameter $1
# is the root of the path, and $2 is the subpath to be created.
#
# The function `dorelease' is recursive.  For the current directory
# and any subdirectories, the files indicated in the text file `releasefiles'
# are copied into the RELEASEDIR heierarchy.  `makepath' is used to
# create any required directories.  The parameter $1 is the name of
# the subdirectory from which `make' was invoked, and $2 is the current
# subdirectory.
#

release :
	@ \
	findpath( ) { \
		THISDIR=`pwd`; \
		while cmp -s makefile ../makefile; do \
			cd ..; \
		done; \
		ROOTDIR=`pwd`; \
		if [ $$THISDIR != $$ROOTDIR ]; then \
			expr $$THISDIR/ : $$ROOTDIR/"\(.*\)"; \
		fi; \
	}; \
	makepath( ) { \
		if [ ! -d $$1$$2 ]; then \
			if [ $$2 ]; then \
				makepath $$1 `echo $$2 | sed 's/[^/]*\/$$//'`; \
			fi; \
			echo mkdir $$1$$2; \
			mkdir $$1$$2; \
		fi; \
	}; \
	dorelease( ) { \
		for PACKAGE in *; do \
			if [ -d $$PACKAGE -a ! -h $$PACKAGE ]; then \
				cd $$PACKAGE; \
				dorelease $$1 $$2$$PACKAGE/; \
				cd ..; \
			fi; \
		done; \
		if [ -s releasefiles ]; then \
			makepath ${RELEASEDIR}/ $$1$$2; \
			for FILE in `cat releasefiles`""; do \
				if [ -f $$FILE ]; then \
					echo cp $$2$$FILE ${RELEASEDIR}/$$1$$2; \
					cp $$FILE ${RELEASEDIR}/$$1$$2; \
				fi; \
			done; \
		fi; \
	}; \
	dorelease `findpath` ""
	touch ${RELEASEDIR}/../.release

#
# `sourcerelease'
#
# The function `findpath' finds the position of the current directory in
# the class heierarchy.
#
# The function `makepath' creates a target directory if neccessary,
# creating any missing parent directories as well.  The parameter $1
# is the root of the path, and $2 is the subpath to be created.
#
# The function `dosourcerelease' is recursive.  `makepath' is used to
# create any required directories.  The parameter $1 is the name of
# the subdirectory from which `make' was invoked, and $2 is the current
# subdirectory.
#

sourcerelease :
	@ \
	findpath( ) { \
		THISDIR=`pwd`; \
		while cmp -s makefile ../makefile; do \
			cd ..; \
		done; \
		ROOTDIR=`pwd`; \
		if [ $$THISDIR != $$ROOTDIR ]; then \
			expr $$THISDIR/ : $$ROOTDIR/"\(.*\)"; \
		fi; \
	}; \
	makepath( ) { \
		if [ ! -d $$1$$2 ]; then \
			if [ $$2 ]; then \
				makepath $$1 `echo $$2 | sed 's/[^/]*\/$$//'`; \
			fi; \
			echo mkdir $$1$$2; \
			mkdir $$1$$2; \
		fi; \
	}; \
	dosourcerelease( ) { \
		for PACKAGE in *; do \
			if [ -d $$PACKAGE -a ! -h $$PACKAGE ]; then \
				cd $$PACKAGE; \
				dosourcerelease $$1 $$2$$PACKAGE/; \
				cd ..; \
			fi; \
		done; \
		if [ "`echo *.java`" != "*.java" ]; then \
			makepath ${SOURCERELEASEDIR}/ $$1$$2; \
			for SOURCEFILE in *.java; do \
				echo copying $${SOURCEFILE}; \
				cat ${SOURCERELEASEDIR}/../sourceheader $${SOURCEFILE} | expand -4 > ${SOURCERELEASEDIR}/$$1$$2/$${SOURCEFILE}; \
			done; \
		fi; \
	}; \
	dosourcerelease `findpath` ""
	cp makefile ${SOURCERELEASEDIR}
	touch ${SOURCERELEASEDIR}/../.source

#
# The target `changepackage' edits the .java files in each subdirectory
# to reflect a change in the package heierarchy.  usage is:
#
# make changepackage OLD=ibook NEW=ibook.v10a2
#

changepackage :
	@ \
	dochangepackage( ) { \
		for PACKAGE in *; do \
			if [ -d $$PACKAGE -a ! -h $$PACKAGE ]; then \
				cd $$PACKAGE; \
				dochangepackage; \
				cd ..; \
			fi; \
		done; \
		for SOURCEFILE in *.java''; do \
			if [ -f $$SOURCEFILE ]; then \
				sed -e '/package ${OLD}/s/package ${OLD}/package ${NEW}/' \
					-e '/import ${OLD}/s/import ${OLD}/import ${NEW}/' \
					$$SOURCEFILE > $$SOURCEFILE.temp; \
				mv $$SOURCEFILE.temp $$SOURCEFILE; \
			fi; \
		done; \
		if [ -f index.html ]; then \
			sed -e '/code=${OLD}/s/code=${OLD}/code=${NEW}/' \
				-e '/code="${OLD}/s/code="${OLD}/code="${NEW}/' \
				index.html >> index.html.temp; \
			mv index.html.temp index.html; \
		fi; \
	}; \
	dochangepackage;

#
# The target `makefiles' creates a makefile in each subdirectory which does
# not have one, by creating a link to this makefile.  It recurses on subdirectories.
# The makefile links can be deleted with `make nomakefiles'.
#
# The function `domakefiles' takes two arguments.  $1 is the name of the
# current directory, and $2 is the name of the makefile to install.  $3 is
# used to save the variable $$PACKAGE during a recursive call.
#
# The command `set "$$1" "$$2" "$$PACKAGE"' is used to preserve the value of the
# PACKAGE variable across a recursive call, by saving it as the postitional
# parameter $3.
#

makefiles :
	@ \
	domakefiles( ) { \
		for PACKAGE in *; do \
			if [ -d $$PACKAGE -a ! -h $$PACKAGE ]; then \
				set "$$1" "$$2" "$$PACKAGE"; \
				cd $$3; \
				domakefiles $$1$$3/ ../$$2; \
				cd ..; \
				if [ ! -f $$3/makefile ]; then \
					echo "ln makefile $$1$$3/makefile"; \
					ln $$2 $$3/makefile; \
				fi; \
			fi; \
		done; \
	}; \
	domakefiles "" makefile

#
# The target `nomakefiles' deletes the makefiles in each subdirectory, as long
# as those makefiles are identical to the current makefile.  The makefiles can
# be recreated with `make makefiles'.
#
# The function `donomakefiles' takes two arguments.  $1 is the name of the
# current directory, and $2 is the name of the makefile to compare with.  $3 is
# used to save the variable $$PACKAGE during a recursive call.
#
# The command `set "$$1" "$$2" "$$PACKAGE"' is used to preserve the value of the
# PACKAGE variable across a recursive call, by saving it as the postitional
# parameter $3.
#

nomakefiles :
	@ \
	donomakefiles( ) { \
		for PACKAGE in *; do \
			if [ -d $$PACKAGE -a ! -h $$PACKAGE ]; then \
				set "$$1" "$$2" "$$PACKAGE"; \
				cd $$3; \
				donomakefiles $$1$$3/ ../$$2; \
				cd ..; \
				if cmp -s $$2 $$3/makefile; then \
					echo "rm -f $$1$$3/makefile"; \
					rm -f $$3/makefile; \
				fi; \
			fi; \
		done; \
	}; \
	donomakefiles "" makefile
